﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;

namespace Exec
{
    /* 플러그인 관리 클래스 */
    public sealed class Manager
    {
        // 식별자(prefix)와 플러그인
        private static Dictionary<string, PlugIn> pis
            = new Dictionary<string, PlugIn>();

        public Manager()
        {        
            Add(@"Core.dll", 1);
            Add(@"Net.dll", 1);
        }

        // 들어온 트랜색션의 신뢰성에 따라 해당 플러그인에 넘김
        public static void Mediate(Transaction tn)
        {
            PlugIn p;

            if (!tn.CheckSize())
            {
                Console.WriteLine("!트랜색션이 제대로된 형태가 아닙니다. ");
                return;
            }

            try
            {
                p = pis[tn.GetPre()];
            }
            catch (Exception ex)
            {
                Console.WriteLine("!없는 플러그인 입니다. " + ex.Message);
                return;
            }

            Comm.Execute(tn);
        }

        /* 
         * 접근 권한에 따라 플러그인 추가.제거 관리 메소드의 권한을 부여한다.
         */

        // 유저 플러그인
        public void Add(String fn)
        {
            Add(fn, 2);
        }

        // 직접적인 추가는 핵심 플러그인이고, 간접적인 추가는 유저 플러그인이다.
        private void Add(string fn, int lv)
        {
            PlugIn p;
            object obj;
            Assembly a = Assembly.LoadFrom(fn);

            Type[] t = a.GetTypes();

            obj = Activator.CreateInstance(t[0]);

            // 플러그인의 인터페이스가 검증되면 추가
            if (obj is IPlugIn)
            {
                p = new PlugIn((IPlugIn)obj, lv);
                
                pis[p.GetPrefix()] = p;
                p.AddNotify();
            }
            else
            {
                Console.WriteLine("!{0} 플러그인이 없거나 인터페이스가 틀립니다.", fn);
            }          
        }

        // prefix로 플러그인 제거
        public void Remove(string pf)
        {
            PlugIn p = pis[pf];

            // 플러그인이 없거나 핵심 플러그인이면 리턴
            if (p == null || p.lv == 1)
            {
                Console.WriteLine("!해당 플러그인이 없거나 레벨1입니다.");
                return;
            }

            p.RemoveNotify();

            pis.Remove(pf);
        }

        // 객체로 플러그인 제거
        public void Remove(PlugIn p)
        {
            Remove(p.GetPrefix());
        }

        // 플러그인 목록 출력
        public void PrintPlugin()
        {
            Console.WriteLine("Name\tLevel\tInfo");

            foreach (KeyValuePair<string, PlugIn> kv in pis)
            {
                kv.Value.GetInfo();
            }
        }
    }
}
